﻿/*CLR Version: 4.0.30319.18408
 * Creat Date: 2015/5/20 11:24:07
 * Creat Year: 2015
 * Creator: 程炜.Snail
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Text.RegularExpressions;
namespace Utility.Extensions
{
    /// <summary>
    /// 日期扩展方法
    /// </summary>
    public static class DateTimeExtensions
    {
        private static Regex reg = new Regex("[\\+\\-][0-9]{1,8}([.]{1}[0-9]{1,2})?$");
        /// <summary>
        /// DateTime 的扩展方法 根据用户输入的时间,将时间更改到用户指定时区
        /// DateTime extension method based on user input time, time will change to the user specified time zone
        /// </summary>
        /// <param name="dt">需要转换的时间(UTC+0时间)(DateTime)</param>
        /// <param name="timezone">时区,格式 UTC+12,UTC-9.5(time zone)</param>
        /// <returns>Date Time</returns>
        public static DateTime GetTimezoneDateTime(this DateTime dt, string timezone = "UTC+0")
        {
            if (string.IsNullOrWhiteSpace(timezone))
            {
                timezone = "UTC+0";
            }
            timezone = timezone.ToUpper().Trim();
            var match = reg.Match(timezone);
            double timeDifference = 0d;
            if (match.Success)
            {
                timeDifference = Convert.ToDouble(match.Value);
            }
            else
            {
                throw new System.Exception("Timezone is error");
            }
            return dt.AddHours(timeDifference);
        }
        /// <summary>
        /// DateTime 的扩展方法
        /// 根据用户输入的时间,将时间更改到用户指定时区
        /// </summary>
        /// <param name="dt">需要转换的时间(UTC+0时间)</param>
        /// <param name="timezone">时区,格式 UTC+12,UTC-9.5</param>
        /// <returns></returns>
        public static DateTime TimezoneDateTime(this DateTime dt, string timezone = "UTC+0")
        {
            if (string.IsNullOrWhiteSpace(timezone))
            {
                timezone = "UTC+0";
            }
            timezone = timezone.ToUpper().Trim();            
            var match = reg.Match(timezone);
            double timeDifference = 0d;
            if (match.Success)
            {
                timeDifference = Convert.ToDouble(match.Value);
            }
            else
            {
                throw new System.Exception("Timezone is error");
            }
            return dt.AddHours(timeDifference);
        }
        /// <summary>
        /// DateTime 的扩展方法
        /// 根据用户输入的时间,判断该时间是一年中的第几周
        /// </summary>
        /// <param name="dateTime"></param>
        /// <param name="cultureInfoName">国家区域编码,默认 zh-CN</param>
        /// <returns></returns>
        public static int WeekOfYear(this DateTime dateTime, string cultureInfoName = "zh-CN")
        {
            return new System.Globalization.CultureInfo("zh-CN").Calendar.GetWeekOfYear(dateTime, System.Globalization.CalendarWeekRule.FirstDay, System.DayOfWeek.Monday);
        }
        /// <summary>
        /// DateTime 的扩展方法
        /// 根据用户输入的时间,获取星期的第一天
        /// </summary>
        /// <param name="dateTime"></param>
        /// <param name="sundayFirst">
        /// true:星期天作为一周的第一天
        /// false: 星期一作为一周的第一天
        /// </param>
        /// <returns></returns>
        public static DateTime WeekFirstDay(this DateTime dateTime, bool sundayFirst = true)
        {
            int weeknow = Convert.ToInt32(dateTime.DayOfWeek);
            //星期一为第一天，weeknow等于0时，要向前推6天。    
            if (!sundayFirst)
            {
                weeknow = (weeknow == 0 ? (7 - 1) : (weeknow - 1));
            }
            int daydiff = (-1) * weeknow;
            return dateTime.AddDays(daydiff);
        }
        /// <summary>
        /// DateTime 的扩展方法
        /// 根据用户输入的时间,获取星期的第一天
        /// </summary>
        /// <param name="dateTime"></param>
        /// <param name="todayLast">
        /// 如果实际时间(今天)的日期小于周的最后一天,是否将实际时间作为该周的最后一天
        /// true: 今天的时间作为本周的最后一天
        /// false: 取本周的实际最后一天时间
        /// </param>
        /// <param name="sundayFirst">
        /// true:星期天作为一周的第一天
        /// false: 星期一作为一周的第一天
        /// </param>
        /// <returns></returns>
        public static DateTime WeekLastDay(this DateTime dateTime, bool todayLast = true, bool sundayFirst = true)
        {
            int weeknow = Convert.ToInt32(dateTime.DayOfWeek);
            //星期一为第一天，weeknow等于0时，要向前推6天。    
            if (!sundayFirst)
            {
                weeknow = (weeknow == 0 ? (7 - 1) : (weeknow - 1));
            }
            int daydiff = (-1) * weeknow;
            DateTime firstWeekDay = dateTime.AddDays(daydiff);
            DateTime lastWeekDay = firstWeekDay.AddDays(6);
            if (todayLast && lastWeekDay.DayOfYear > DateTime.Now.DayOfYear)
            {
                lastWeekDay = DateTime.Now;
            }
            return lastWeekDay;
        }
        /// <summary>
        /// DateTime 的扩展方法
        /// 根据用户输入的时间,获取月的第一天
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static DateTime MonthFirstDay(this DateTime dateTime)
        {
            return new DateTime(dateTime.Year, dateTime.Month, 1);
        }
        /// <summary>
        /// DateTime 的扩展方法
        /// 根据用户输入的时间,获取月的最后一天
        /// </summary>
        /// <param name="dateTime"></param>
        /// 如果实际时间(今天)的日期小于月的最后一天,是否将实际时间作为该月的最后一天
        /// true: 今天的时间作为月的最后一天
        /// false:取月的实际最后一天时间
        /// <returns></returns>
        public static DateTime MonthLastDay(this DateTime dateTime, bool todayLast = true)
        {
            int day = DateTime.DaysInMonth(dateTime.Year, dateTime.Month);
            DateTime lastDay = new DateTime(dateTime.Year, dateTime.Month, day);
            if (todayLast && lastDay.DayOfYear > DateTime.Now.DayOfYear)
            {
                lastDay = DateTime.Now;
            }
            return lastDay;
        }
        /// <summary>
        /// 获取指定日期的季度的第一天
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static DateTime QuarterFirstDay(this DateTime dateTime)
        {
            return dateTime.AddMonths(0 - (dateTime.Month - 1) % 3).AddDays(1 - dateTime.Day);
        }
        /// <summary>
        /// 获取指定日期的季度的最后一天
        /// </summary>
        /// <param name="dateTime"></param>
        /// <param name="todayLast">
        /// 如果实际时间(今天)的日期小于季度的最后一天,是否将实际时间作为该季度的最后一天
        /// true: 今天的时间作为季度的最后一天
        /// false:取季度的实际最后一天时间
        /// </param>
        /// <returns></returns>
        public static DateTime QuarterLastDay(this DateTime dateTime, bool todayLast = true)
        {
            DateTime quartTime = dateTime.AddMonths(0 - (dateTime.Month - 1) % 3).AddDays(1 - dateTime.Day).AddMonths(3).AddDays(-1);
            if (todayLast && quartTime.DayOfYear > DateTime.Now.AddDays(-1).DayOfYear)
            {
                return DateTime.Now;
            }
            return quartTime;
        }
        /// <summary>
        /// 获取指定时间是第几季度
        /// </summary>
        /// <param name="dateTime"></param>
        /// <param name="quarterString">
        /// 所有季度的组合的字符串,
        /// 默认中文:一季度,二季度,三季度,四季度
        /// </param>
        /// <param name="splitChar">
        /// 分割各季度的字符
        /// 默认: ,
        /// </param>
        /// <returns></returns>
        public static string Quarter(this DateTime dateTime, string quarterString = "一季度,二季度,三季度,四季度", char splitChar = ',')
        {
            string[] quarterArray = quarterString.Split(splitChar);
            switch (dateTime.Month)
            {
                case 1:
                case 2:
                case 3:
                    return quarterArray[0];
                case 4:
                case 5:
                case 6:
                    return quarterArray[1];
                case 7:
                case 8:
                case 9:
                    return quarterArray[2];
                default:
                    return quarterArray[3];
            }
        }
        /// <summary>
        /// 获取指定日期的年份的第一天
        /// </summary>
        /// <param name="dateTime"></param>
        /// <returns></returns>
        public static DateTime YearFirstDay(this DateTime dateTime)
        {
            return new DateTime(dateTime.Year, 1, 1);
        }
        /// <summary>
        /// 获取指定日期的年份的最后一天
        /// </summary>
        /// <param name="dateTime"></param>
        /// <param name="todayLast">
        /// 如果实际时间(今天)的日期小于年份的最后一天,是否将实际时间作为该年份的最后一天
        /// true: 今天的时间作为年份的最后一天
        /// false:取年份的实际最后一天时间
        /// </param>
        public static DateTime YearLastDay(this DateTime dateTime, bool todayLast = true)
        {
            DateTime yearTime = DateTime.Now.AddYears(1).AddDays(-1);
            if (todayLast && yearTime.DayOfYear > DateTime.Now.AddDays(-1).DayOfYear)
            {
                return DateTime.Now;
            }
            return yearTime;
        }

        /// <summary>
        /// 将GMT转成 DataTime格式
        /// </summary>
        /// <param name="timeOutDate"></param>
        /// <returns></returns>
        public static DateTime ToDateTime(this long timeOutDate)
        {
            return new DateTime(new DateTime(1970, 1, 1).Ticks + timeOutDate * 10000 + System.TimeZoneInfo.Local.GetUtcOffset(DateTime.Now).Hours * 3600 * (long)10000000);
        }
        /// <summary>
        ///将DateTime转换成Unix时间
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static long ToUnix(this DateTime time)
        {
            return (long)(time.ToUniversalTime() - DateTime.Parse("1970-1-1")).TotalMilliseconds;
        }
        /// <summary>
        ///将DateTime转换成Unix时间
        /// </summary>
        /// <param name="time"></param>
        /// <returns></returns>
        public static long? ToUnix(this DateTime? time)
        {
            if (null == time)
            {
                return null;
            }
            return (long)(((DateTime)time).ToUniversalTime() - DateTime.Parse("1970-1-1")).TotalMilliseconds;
        }
    }
}